package com.colabo.j2ee.web.core.exception;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Date;

/**
 * an wrapped exception for inherited. any user customized exception should extends this.
 * @author Anthony Do
 * @since 2009-12-22
 */
public class WrappedException extends Exception implements java.io.Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -7610617132897541723L;
	
	/**
	 * exception cause
	 */
	protected Throwable t;
	
	/**
	 * string information from stack trace of the exception
	 */
	public String stackTraceString;

	/**
	 * //得到抛异常时所在的类
	 */
	protected String rootClassName;
	
	/**
	 * //得到抛异常时所在的类方法
	 */
	protected String rootMethodName;
	
	/**
	 * default constructor
	 */
	public WrappedException() {
		super();
	}

	/**
	 * constructor with an additional information 
	 */
	public WrappedException(final String msg) {
		super(msg); 
	}

	/**
	 * constructor with a resource(exception chain)
	 */
	public WrappedException(Throwable ex) {
		super(ex);
		stackTraceString = extractStackTraceString(ex);
	}

	/**
	 * constructor with an additional information and a resource(exception chain)
	 */
	public WrappedException(String msg, Throwable ex) {
		super(msg, ex);
		stackTraceString = extractStackTraceString(ex);
	}

	/**
	 * output the stack trace information in string form
	 * @return string of the stack trace's information or "" if an exception been caught
	 */
	public String extractStackTraceString(Throwable ex) {
		StringWriter s = new StringWriter();
		ex.printStackTrace(new PrintWriter(s)); 
		String st = s.toString();
		try {
			s.close();
		} catch (IOException e) {
			return "";
		}
		return st;
	}

	/**
	 * get the stack trace information
	 * @return the string form of the stack trace information
	 */
	public String getStackTraceString() {
		if (getCause() == null) {
			return "";
		}
		StringBuffer sb = new StringBuffer();
		sb.append(stackTraceString);
		return sb.toString();
	}

	/**
	 * override the Throwable.getMessage()
	 * @return the message with the nested throwable object's message
	 */
	@Override
	public String getMessage() {
		if (getCause() == null) {
			return "";
		}
		String superMsg = super.getMessage();
		StringBuffer sb = new StringBuffer();
		String nestedMsg = getCause().getMessage();
		if (superMsg == null) {
			sb.append(nestedMsg);
		} else {
			sb.append(superMsg).append(": ").append(nestedMsg);
		}
		return sb.toString();
	}

	/**
	 * override the Throwable.toString()
	 * 
	 */
	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();
		sb.append(super.toString()); 
		if (getCause() != null) {
			sb.append("; \n\t---> nested ");
			sb.append(getCause());
		}
		return sb.toString();
	}
	
	/**
	 * 把异常的堆栈信息转为xml形式,不需要保存到文件中
	 */
	public String getXMLStackTraceString(MessageException me) {
		String xml="";
		if (me == null) {
			return null;
		}
		if(t==null){
		//如果没有异常源对象
			xml=me.getTip(); 
			return xml;
		}
		int deepth = t.getStackTrace().length;
		if (rootClassName == null || rootClassName.trim().length() == 0) {
			rootClassName = t.getStackTrace()[deepth - 1].getClassName();
		}
		if (rootMethodName == null || rootMethodName.trim().length() == 0) {
			rootMethodName = t.getStackTrace()[deepth - 1].getMethodName();
		}
		
		ExceptionStatistics es = new ExceptionStatistics();
		es.setTraceEnabled(true);
		if (me instanceof ServiceException) {
			es.updateStatistics((ServiceException) me, rootMethodName, rootClassName, new Date());
		} else if (me instanceof CommonException) {
			es.updateStatistics((CommonException) me, rootMethodName, rootClassName, new Date());
		}else if (me instanceof DAOException) {
			es.updateStatistics((DAOException) me, rootMethodName, rootClassName, new Date());
		}else if (me instanceof MediatorException) {
			es.updateStatistics((MediatorException) me, rootMethodName, rootClassName, new Date());
		}
		xml = es.toXML();
		es.reset();
		return "\n" + xml;
	}

	/**
	 * 把异常的堆栈信息转为xml形式,同时在后台自动保存到指定的文件中
	 * 
	 * @param me
	 * @param filePath
	 *            相对路径：类似“test/com/cib/resources/exception-stats-2008.xml”
	 *            绝对路径： 类似“C:/exception-stats-2008.xml”
	 * @return
	 */
	public String getXMLStackTraceString(MessageException me, String filePath) {
		String xml="";
		if (me == null) {
			return null;
		}
		if(t==null){
			xml=me.getTip();
			return xml;
		}
		// 得到异常的堆栈深度，以便下面取出抛异常时所在的类和方法
		int deepth = t.getStackTrace().length;
		// 得到抛异常时所在的类
		if (rootClassName == null || rootClassName.trim().length() == 0) {
			rootClassName = t.getStackTrace()[deepth - 1].getClassName();
		}
		// 得到抛异常时所在的方法
		if (rootMethodName == null || rootMethodName.trim().length() == 0) {
			rootMethodName = t.getStackTrace()[deepth - 1].getMethodName();
		}
		ExceptionStatistics es = new ExceptionStatistics();
		es.setPersistenceStorage(filePath);
		es.setTraceEnabled(true);
		if (me instanceof ServiceException) {
			es.updateStatistics((ServiceException) me, rootMethodName, rootClassName, new Date());
		} else if (me instanceof CommonException) {
			es.updateStatistics((CommonException) me, rootMethodName, rootClassName, new Date());
		}else if (me instanceof DAOException) {
			es.updateStatistics((DAOException) me, rootMethodName, rootClassName, new Date());
		}else if (me instanceof MediatorException) {
			es.updateStatistics((MediatorException) me, rootMethodName, rootClassName, new Date());
		}
		  xml = es.toXML();
		es.persist();
		es.reset();
		return "\n" + xml;
	}
}
